package com.morningstar.flow.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.morningstar.common.dao.entity.CommonQuery;
import com.morningstar.common.result.Result;
import com.morningstar.flow.constants.FlowStatus;
import com.morningstar.flow.controller.request.StartProcessEntity;
import com.morningstar.flow.controller.result.FlowTask;
import com.morningstar.flow.dao.entity.FlowInstance;
import com.morningstar.flow.dao.entity.FlowNodeCopy;
import com.morningstar.flow.dao.entity.FlowProcess;
import com.morningstar.flow.service.FlowInstanceService;
import com.morningstar.flow.service.FlowNodeCopyService;
import com.morningstar.flow.service.FlowProcessService;
import com.morningstar.system.api.feign.ISystemUserFeign;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.TaskService;
import org.flowable.task.api.Task;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.morningstar.common.constants.permission.PermissionConstants.*;

/**
 * 流程实列控制器
 */
@Slf4j
@RestController
@RequestMapping("/flow/instance")
public class FlowInstanceController {

    private static final String PERMISSION = "flow.instance";
    private static final String PERMISSION_LIST = PERMISSION + LIST;
    private static final String PERMISSION_DETAIL = PERMISSION + DETAIL;
    private static final String PERMISSION_DELETE = PERMISSION + DELETE;
    private static final String PERMISSION_START = PERMISSION + ".start";
    private static final String PERMISSION_REVOCATION = PERMISSION + ".revocation";
    private static final String PERMISSION_MY_START = PERMISSION + ".my.start";
    private static final String PERMISSION_MY_COPY = PERMISSION + ".my.copy";

    @Resource
    private TaskService taskService;

    @Resource
    private FlowInstanceService flowInstanceService;

    @Resource
    private FlowNodeCopyService flowNodeCopyService;

    @Resource
    private FlowProcessService flowProcessService;

    @Resource
    private ISystemUserFeign systemUserFeign;

    /**
     * 我发起的流程实列
     *
     * @param commonQuery 通用查询
     * @return 基本结果类
     */
    @PostMapping("/myStart")
    @SaCheckPermission(PERMISSION_MY_START)
    public Result<IPage<FlowInstance>> myStart(@RequestBody CommonQuery<FlowInstance, FlowInstance> commonQuery) {
        FlowInstance query = commonQuery.getQuery();
        LambdaQueryWrapper<FlowInstance> queryWrapper = new LambdaQueryWrapper<>();
        if (query != null) {
            queryWrapper.eq(query.getProcessId() != null, FlowInstance::getProcessId, query.getProcessId());
        }
        queryWrapper.eq(FlowInstance::getStartUserId, StpUtil.getLoginId().toString());
        queryWrapper.orderByDesc(FlowInstance::getCreateTime);
        IPage<FlowInstance> result = flowInstanceService.page(commonQuery.getPage(), queryWrapper);
        dealInstance(result, false);
        return Result.successData(result);
    }

    /**
     * 抄送我的流程实例
     *
     * @param commonQuery 通用查询
     * @return 基本结果类
     */
    @PostMapping("/myCopy")
    @SaCheckPermission(PERMISSION_MY_COPY)
    public Result<IPage<FlowInstance>> myCopy(@RequestBody CommonQuery<FlowInstance, FlowNodeCopy> commonQuery) {
        String userId = StpUtil.getLoginId().toString();
        FlowNodeCopy query = commonQuery.getQuery() == null ? new FlowNodeCopy() : commonQuery.getQuery();
        query.setUserId(Long.valueOf(userId));
        IPage<FlowInstance> result = flowNodeCopyService.copyList(commonQuery.getPage(), query);
        dealInstance(result, false);
        return Result.successData(result);
    }

    /**
     * 流程实列列表
     *
     * @param commonQuery 通用查询
     * @return 基本结果类
     */
    @PostMapping("/list")
    @SaCheckPermission(PERMISSION_LIST)
    public Result<IPage<FlowInstance>> list(@RequestBody CommonQuery<FlowInstance, FlowInstance> commonQuery) {
        FlowInstance query = commonQuery.getQuery();
        LambdaQueryWrapper<FlowInstance> queryWrapper = new LambdaQueryWrapper<>();
        if (query != null) {
            queryWrapper.eq(query.getProcessId() != null, FlowInstance::getProcessId, query.getProcessId());
        }
        queryWrapper.orderByDesc(FlowInstance::getCreateTime);
        IPage<FlowInstance> result = flowInstanceService.page(commonQuery.getPage(), queryWrapper);
        dealInstance(result, true);
        return Result.successData(result);
    }


    /**
     * 草稿
     *
     * @param startProcessEntity 发起流程实体
     * @return 基本结果类
     */
    @PostMapping("/draft")
    @SaCheckPermission(PERMISSION_START)
    public Result<Object> draft(@RequestBody StartProcessEntity startProcessEntity) {
        flowInstanceService.draft(startProcessEntity);
        return Result.successNoData();
    }


    /**
     * 发起流程
     *
     * @param startProcessEntity 发起流程实体
     * @return 基本结果类
     */
    @PostMapping("/start")
    @SaCheckPermission(PERMISSION_START)
    public Result<Object> start(@RequestBody StartProcessEntity startProcessEntity) {
        String instanceId = flowInstanceService.start(startProcessEntity);
        return Result.successData(instanceId);
    }

    /**
     * 流程实列详细信息
     *
     * @param instanceId 流程实列Id
     * @return 流程实例
     */
    @GetMapping("/detail/{instanceId}")
    @SaCheckPermission(PERMISSION_DETAIL)
    public Result<FlowInstance> detail(@PathVariable("instanceId") Long instanceId) {
        FlowInstance flowInstance = flowInstanceService.getById(instanceId);
        FlowProcess process = flowProcessService.getById(flowInstance.getProcessId());
        Map<Long, String> userIdAndName = systemUserFeign.selectUserIdAndName();
        dealInstance(flowInstance, process, userIdAndName, true);
        return Result.successData(flowInstance);
    }

    /**
     * 删除流程草稿
     *
     * @param instanceId 流程实例Id
     * @return 基本结果类
     */
    @GetMapping("/delete")
    @SaCheckPermission(PERMISSION_DELETE)
    public Result<Object> delete(@RequestParam String instanceId) {
        LambdaQueryWrapper<FlowInstance> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FlowInstance::getInstanceId, instanceId);
        queryWrapper.eq(FlowInstance::getStatus, FlowStatus.FLOW_STATUS_DRAFT);
        if (flowInstanceService.remove(queryWrapper)) {
            return Result.successNoData();
        }
        return Result.fail("删除失败,请刷新页面");
    }

    /**
     * 撤销流程
     *
     * @param processInstanceId 流程实列Id
     * @return 基本结果类
     */
    @GetMapping("/revocation")
    @SaCheckPermission(PERMISSION_REVOCATION)
    public Result<Object> revocation(@RequestParam String processInstanceId) {
        return flowInstanceService.revocation(processInstanceId);
    }

    /**
     * 处理流程数据
     *
     * @param result 分页结果
     */
    private void dealInstance(IPage<FlowInstance> result, boolean queryTask) {
        Map<Long, String> userIdAndName = systemUserFeign.selectUserIdAndName();
        Map<Long, FlowProcess> flowProcessMap = flowProcessService.list()
                .stream()
                .collect(Collectors.toMap(FlowProcess::getProcessId, item -> item));
        result.getRecords().forEach(item -> {
            FlowProcess flowProcess = flowProcessMap.get(item.getProcessId());
            dealInstance(item, flowProcess, userIdAndName, queryTask);
        });
    }

    /**
     * 处理流程数据
     *
     * @param flowInstance  流程实例
     * @param userIdAndName 用户Id和名称
     * @param flowProcess   流程数据
     * @param queryTask     是否查询任务  true 查询  false 不查询
     */
    private void dealInstance(FlowInstance flowInstance, FlowProcess flowProcess,
                              Map<Long, String> userIdAndName, boolean queryTask) {

        if (flowProcess != null) {
            flowInstance.setFlowProcess(flowProcess);
            flowInstance.setProcessName(flowProcess.getProcessName());
            flowInstance.setStartUserName(userIdAndName.get(flowInstance.getStartUserId()));
        }
        if (!queryTask) {
            return;
        }
        if (StringUtils.isBlank(flowInstance.getProcessInstanceId())) {
            return;
        }
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(flowInstance.getProcessInstanceId()).list();
        List<FlowTask> flowTasks = new ArrayList<>();
        for (Task task : taskList) {
            FlowTask flowTask = new FlowTask();
            flowTask.setTaskId(task.getId());
            flowTask.setTaskName(task.getName());
            flowTask.setAssignee(task.getAssignee());
            try {
                flowTask.setAssigneeName(userIdAndName.get(Long.parseLong(task.getAssignee())));
            } catch (Exception e) {
                flowTask.setAssigneeName(task.getAssignee());
            }
            flowTask.setCreateTime(task.getCreateTime());
            flowTask.setTaskDefinitionKey(task.getTaskDefinitionId());
            flowTasks.add(flowTask);
        }
        flowInstance.setFlowTaskList(flowTasks);
    }

}
